#include "MediaSession.h"
#include "JingleExtension.h"
#include "JingleManager.h"

namespace cm_nat
{
    class JingleManager;

    MediaSession::MediaSession(): m_listener(NULL)
    {

    }

    MediaSession::~MediaSession()
    {

    }

    void MediaSession::registerLisener( MediaSessionListener* p_listener )
    {
        m_listener = p_listener;
    }

    int MediaSession::initiate()
    {
        return CM_RES_SUCCESS;
    }

    int MediaSession::accept()
    {
        return CM_RES_SUCCESS;
    }

    int MediaSession::reject()
    {

        return CM_RES_SUCCESS;
    }

    int MediaSession::terminate()
    {

        return CM_RES_SUCCESS;
    }

    int MediaSession::sendSessionInitiate()
    {
        JingleExtension* p_je = new JingleExtension;;
        p_je->setSessionID( m_sid );
        p_je->setInitiator( m_jid.full() );
        p_je->setAction("session-initiate");

        IQ iq(IQ::Set,m_peerJid);
        iq.addExtension(p_je);

        m_jingleManager->send( iq );

        return CM_RES_SUCCESS;
    }

    int MediaSession::sendSessionAccept()
    {
        JingleExtension* p_je = new JingleExtension;;
        p_je->setSessionID( m_sid );
        p_je->setInitiator( m_jid.full() );
        p_je->setAction("session-accept");

        IQ iq(IQ::Set,m_peerJid);
        iq.addExtension(p_je);

        m_jingleManager->send( iq );

        return CM_RES_SUCCESS;
    }

    int MediaSession::sendCandidate(SocketAddress reflexAddress)
    {
        Candidate* p_candidate = new Candidate;
        p_candidate->m_rel_addr = reflexAddress.host().toString();
        p_candidate->m_rel_port = reflexAddress.port();

        Transport* p_transport = new Transport;
        p_transport->addCandidate( p_candidate );

        Content* p_content = new Content;
        p_content->setCreator("initiator");
        p_content->setName("media");
        p_content->addTransport( p_transport );

        JingleExtension* p_je = new JingleExtension;
        p_je->setSessionID( m_sid );
        p_je->setInitiator( m_jid.full() );
        p_je->setAction("exchange-candidate");

        p_je->addContent( p_content );

        IQ iq(IQ::Set,m_peerJid);
        iq.addExtension(p_je);

        m_jingleManager->send( iq );

        return CM_RES_SUCCESS;
    }

    int MediaSession::sendPeerCheckResult(int result, SocketAddress peerReflexAddress)
    {
        JingleExtension* p_je = new JingleExtension;
        p_je->setSessionID( m_sid );
        p_je->setInitiator( m_jid.full() );
        p_je->setAction("check-result");

        if( result == CHECK_RES_SUCCESS ){

            Candidate* p_candidate = new Candidate;
            p_candidate->m_rel_addr = peerReflexAddress.host().toString();
            p_candidate->m_rel_port = peerReflexAddress.port();

            Transport* p_transport = new Transport;
            p_transport->addCandidate( p_candidate );

            Content* p_content = new Content;
            p_content->setCreator("initiator");
            p_content->setName("media");
            p_content->addTransport( p_transport );

            p_je->addContent( p_content );
        }

        IQ iq(IQ::Set,m_peerJid);
        iq.addExtension(p_je);

        m_jingleManager->send( iq );

        return CM_RES_SUCCESS;
    }

    int MediaSession::sendSelectCandidate(bool res, SocketAddress reflexAddress, SocketAddress peerAddress)
    {
        JingleExtension* p_je = new JingleExtension;
        p_je->setSessionID( m_sid );
        p_je->setInitiator( m_jid.full() );
        p_je->setAction("select-candidate");

        if( res == true ){

            Candidate* p_candidate = new Candidate;
            //local select refelx address
            p_candidate->m_ip = reflexAddress.host().toString();
            p_candidate->m_port = reflexAddress.port();

            //remote select refelx address
            p_candidate->m_rel_addr = peerAddress.host().toString();
            p_candidate->m_rel_port = peerAddress.port();

            Transport* p_transport = new Transport;
            p_transport->addCandidate( p_candidate );

            Content* p_content = new Content;
            p_content->setCreator("initiator");
            p_content->setName("media");
            p_content->addTransport( p_transport );

            p_je->addContent( p_content );
        }

        IQ iq(IQ::Set,m_peerJid);
        iq.addExtension(p_je);

        m_jingleManager->send( iq );

        return CM_RES_SUCCESS;

    }


    int MediaSession::parseJingleTag(const Tag* p_tag)
    {
        std::string action = p_tag->findAttribute("action");

        if( action == "session-initiate")
        {
            if( m_listener ){
                m_listener->onInitiate( this );
            }
        }
        else if(action == "session-accept")
        {
            if( m_listener ){
                m_listener->onAccept( this );
            }
        }
        else if( action == "exchange-candidate")
        {
            ConstTagList& candidates = p_tag->findTagList("/jingle/content/transport/candidate" );
            ConstTagList::const_iterator it = candidates.begin();
            for( ; it != candidates.end(); ++it ){
                m_peerCandiate.parse( (*it) );
                if( m_listener ){
                    m_listener->onCandidate( this, &m_peerCandiate );
                }
            }

        }
        else if( action == "check-result" )
        {
            const Tag* candidate = p_tag->findTag("/jingle/content/transport/candidate");
            if( candidate ){
                if(m_listener ){
                    m_listener->onCheckResult(this, CHECK_RES_SUCCESS );
                }
            }else{
                if(m_listener ){
                    m_listener->onCheckResult(this, CHECK_RES_FAIL);
                }
            }
        }
        else if(action == "select-candidate" )
        {
            const Tag* candidate = p_tag->findTag("/jingle/content/transport/candidate");

            Candidate cand;
            if( candidate ){
                if(m_listener ){
                    cand.parse( candidate );
                    m_listener->onSelectCandidate(this, &cand);
                }
            }else{
                if(m_listener ){
                    m_listener->onSelectCandidate(this, &cand);
                }
            }

        }

        return CM_RES_SUCCESS;
    }

}